'''
Created on 23/03/2010

@author: eh01
'''
from datastore.resource import Resource
from runtime.task import Task
from reference.admintask import AdminTask
from string import Template
import re
import logging

class AppTask(Task):
    """This class is a daemon task.    

    *Usage examples*::

        example code

    *Common Arguments for Class methods*:
        <arguments>
    
    *Audience*:
        <audience>
    
    *Constants*:
        .. data:: constant_1
        
            constant_1 is used for ......
        
        .. data:: constant_2
        
            constant_2 is used for ......
    """
    
    application_types = ['Planning Permit', 'Certification of Subdivision', 'Planning Permit and Certification']
    spear_related_options = {'Refer SPEAR application':AdminTask.SPEAR_INTEGRATION_CONFIGURATION_PARAM_SPEAR_ADAPTOR_REFERRAL_URL, 
                             'View SPEAR application':AdminTask.SPEAR_INTEGRATION_CONFIGURATION_PARAM_SPEAR_ADAPTOR_APPLICATION_URL, 
                             'Go to SPEAR':AdminTask.SPEAR_INTEGRATION_CONFIGURATION_PARAM_SPEAR_ADAPTOR_LOGIN_URL}
    
    def cb_start(self, method, uri, new_uri, result, context, **kwargs):
        """This function is called when the task starts. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        
        self.logger.log(logging.DEBUG, "***************** uri (%s), new_uri (%s)" % (uri, new_uri))
        
        # Make sure we look for ALL Uris that are children of our task Uri.
        # (i.e. make a collection of our Uri. 
        #
        # All 'put' messages to this task are interpreted as requests for Spaces Resources.
        #
        
        self.spaces_context.process(uri.app, get='cb_generate_create_app_view')
        self.spaces_context.process(uri.new.app, put='cb_get_new_app')
        self.spaces_context.process(uri.link.app, put='cb_link_app')
        self.spaces_context.process_all(uri.view.app.collection(True), get='cb_generate_app_view')
        self.spaces_context.process(uri.app.collection(True), put='cb_create_application')
        self.spaces_context.process(uri.applist, get='cb_get_app_list')
    
    def cb_link_app(self, method, uri, return_value, result, context, **kwargs):
        """This cb links the CPS application to a SPEAR application. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        rs = Resource()
        post_data = return_value.get_var(Resource.KEY_URI_SERVICES_TYPE_HTTP_REQUEST_DATA)
        spear_reference_number = post_data['spear_reference_number']
        if not self.check_spear_reference(spear_reference_number):
            rs.error_message = '''The SPEAR Reference Number supplied is an incorrect format. It 
            should be in the form of "SnnnnnnX" where 'S' is the letter 'S' and 'n' is a digit 0-9 
            and 'X' is a letter A- Z'''
        rs.set_var(Resource.KEY_URI_SERVICES_TYPE_HTTP_SITE_ACTION_RESULT, 'link-app')
        # call the spear adaptor to get the application
        # when it returns, save the application to spaces then 
        # return the uri of the new application to the caller
        id = context.uuid()
        request_uri = uri.requests.add(str(id))
        context.put(request_uri.response, rs)
        return (True, request_uri.uri_copy())   
    
    def cb_get_new_app(self, method, uri, return_value, result, context, **kwargs):
        """This cb gets a new application from the SPEAR adaptor. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        rs = Resource()
        post_data = return_value.get_var(Resource.KEY_URI_SERVICES_TYPE_HTTP_REQUEST_DATA)
        spear_reference_number = post_data['spear_reference_number']
        if not self.check_spear_reference(spear_reference_number):
            rs.error_message = '''The SPEAR Reference Number supplied is an incorrect format. It 
            should be in the form of "SnnnnnnX" where 'S' is the letter 'S' and 'n' is a digit 0-9 
            and 'X' is a letter A- Z'''
        rs.set_var(Resource.KEY_URI_SERVICES_TYPE_HTTP_SITE_ACTION_RESULT, 'new-app')
        # call the spear adaptor to get the new application
        # when it returns, save the application to spaces then 
        # return the uri of the new application to the caller
        id = context.uuid()
        request_uri = uri.requests.add(str(id))
        context.put(request_uri.response, rs)
        return (True, request_uri.uri_copy())   
        
    def cb_generate_app_view(self, method, uri, return_value, result, context, **kwargs):
        """This cb returns data required to generate the application view. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        app_id = uri.split2()[-1]
        task_uri = context.uri('task:')
        app_rs = context.get(task_uri.eplanning.reference.apptask.app.add(app_id))
        spear_integration_configuration_resource = context.get(task_uri.eplanning.reference.admintask.add('spear-integration-configuration'))
        # hack right now so that there is a optional and mandatory actions for application
        app_rs.optional_actions = []
        app_rs.mandatory_actions = []
        
        form_res = Resource()
        form_res.application = app_rs
        spear_application_actions = []
        if app_rs.spear_reference_number:
            for key, value in AppTask.spear_related_options.items():
                template = Template(spear_integration_configuration_resource.get_var(value))
                spear_application_actions.append((key, template.substitute(srn=app_rs.spear_reference_number)))
        form_res.spear_application_actions = spear_application_actions
        
        return (True, form_res)
        
    def cb_generate_create_app_view(self, method, uri, return_value, result, context, **kwargs):
        """This cb returns data required to generate the create application view. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        data_res = Resource()
        data_res.application_types = AppTask.application_types
        return (True, data_res)
        
    def cb_create_application(self, method, uri, return_value, result, context, **kwargs):
        """This cb creates a application resource and places it in spaces. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
                
        app_rs = Resource()
        app_rs.set_metadata(Resource.KEY_URI_DATASTORE_RESOURCE_TYPE, Resource.KEY_URI_REFERENCE_TYPE_APPLICATION)
        post_data = return_value.get_var(Resource.KEY_URI_SERVICES_TYPE_HTTP_REQUEST_DATA)
        app_rs.property = post_data['property']
        app_rs.applicant_contact = post_data['applicant_contact']
        app_rs.type = post_data['type']
        app_rs.council_reference_number = post_data['council_reference_number']
        app_rs.lodged_at_council = post_data['lodged_at_council']
        if 'spear_reference_number' in post_data:
            app_rs.spear_reference_number = post_data['spear_reference_number']
        else:
            app_rs.spear_reference_number = None
        id = context.uuid()
        app_rs.set_id(id)
        app_uri = uri.add(id)
        context.put(app_uri, app_rs)
        return (True, app_uri)
    
    def cb_get_app_list(self, method, uri, return_value, result, context, **kwargs):
        """This cb returns the application resources in a single resource. 
        
        :param method: <class> or <type>
        :param uri: The task Uri.
        :param new_uri: <class> or <type>
        :param result: <class> or <type>
        :param context: <class> or <type>
        :param kwargs: <class> or <type>
        """
        data_res = Resource()
        data_res.applications = []
        uri_task = context.uri('task:')
        spear_integration_configuration_resource = context.get(uri_task.eplanning.reference.admintask.add('spear-integration-configuration'))
        data_res.set_var(AdminTask.SPEAR_INTEGRATION_CONFIGURATION_PARAM_SPEAR_ADAPTOR_APPLICATION_LIST_URL, 
                         spear_integration_configuration_resource.get_var(AdminTask.SPEAR_INTEGRATION_CONFIGURATION_PARAM_SPEAR_ADAPTOR_APPLICATION_LIST_URL))
        apps_uri = uri_task.eplanning.reference.apptask.app.collection(True)
        uri_list = context.find(apps_uri)
        for uri in uri_list:
            app_res = context.get(uri)
            data_res.applications.append(app_res)
        return (True, data_res)

    # Given the numeric portion of the SPEAR reference number, calculate the check character.
    def calculate_spear_reference(self, num):
            total = 0
            mult = 7
            for n in num:
                    total += int(n) * mult
                    mult -= 1
            return 'AVTSPMJHECBA'[total % 11]
    
    # Validate the format (Snnnnnnx) and check character of a SPEAR reference number.
    def check_spear_reference(self, ref):
        match = re.match('^S(\d{6})([ABCEHJMPSTV]{1})$', ref)
        if match is not None:
                if self.calculate_spear_reference(match.group(1)) == match.group(2):
                        return True
        return False